home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Atari Mega Archive 2
/
Atari Mega Archive CD - Volume 2.iso
/
linux
/
tools
/
gtar10.lha
/
create.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-09-09
|
31KB
|
1,316 lines
/* Create a tar archive.
Copyright (C) 1988 Free Software Foundation
This file is part of GNU Tar.
GNU Tar is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
GNU Tar is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Tar; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/*
* Create a tar archive.
*
* Written 25 Aug 1985 by John Gilmore, ihnp4!hoptoad!gnu.
*
* @(#)create.c 1.36 11/6/87 - gnu
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#ifndef V7
#include <fcntl.h>
#endif
#ifndef __MSDOS__
#include <sys/file.h>
#include <sys/param.h> /* for MAXPATHLEN */
#include <pwd.h>
#include <grp.h>
#endif
#ifdef BSD42
#include <sys/dir.h>
#else
#ifdef __MSDOS__
#include "msd_dir.h"
#else
#ifdef USG
#ifdef NDIR
#include <ndir.h>
#else
#include <dirent.h>
#endif
#ifndef DIRECT
#define direct dirent
#endif
#define DP_NAMELEN(x) strlen((x)->d_name)
#else
/*
* FIXME: On other systems there is no standard place for the header file
* for the portable directory access routines. Change the #include line
* below to bring it in from wherever it is.
*/
#include "ndir.h"
#endif
#endif
#endif
#ifndef DP_NAMELEN
#define DP_NAMELEN(x) (x)->d_namlen
#endif
#ifdef USG
#include <sys/sysmacros.h> /* major() and minor() defined here */
#endif
/*
* V7 doesn't have a #define for this.
*/
#ifndef O_RDONLY
#define O_RDONLY 0
#endif
/*
* Most people don't have a #define for this.
*/
#ifndef O_BINARY
#define O_BINARY 0
#endif
#ifndef MAXPATHLEN
#define MAXPATHLEN 1024
#endif
#include "tar.h"
#include "port.h"
extern struct stat hstat; /* Stat struct corresponding */
#ifndef __MSDOS__
extern dev_t ar_dev;
extern ino_t ar_ino;
#endif
/* JF */
extern struct name *gnu_list_name;
/*
* If there are no symbolic links, there is no lstat(). Use stat().
*/
#ifndef S_IFLNK
#define lstat stat
#endif
#ifndef __STDC__
extern char *malloc();
extern char *strcpy();
extern char *strncpy();
extern void bzero();
extern void bcopy();
#endif
extern int errno;
extern void print_header();
union record *start_header();
void finish_header();
void finduname();
void findgname();
char *name_next();
void to_oct();
void dump_file();
/* This code moved from tar.h since create.c is the only file that cares
about 'struct link's. This means that other files might not have to
include sys/types.h any more.
*/
struct link {
struct link *next;
dev_t dev;
ino_t ino;
short linkcount;
char name[1];
};
struct link *linklist; /* Points to first link in list */
static nolinks; /* Gets set if we run out of RAM */
/*
* "Scratch" space to store the information about a sparse file before
* writing the info into the header or extended header
*/
/* struct sp_array *sparsearray;*/
/* number of elts storable in the sparsearray */
/*int sparse_array_size = 10;*/
void
create_archive()
{
register char *p;
char *name_from_list();
open_archive(0); /* Open for writing */
if(f_gnudump) {
char buf[MAXNAMLEN],*q,*bufp;
collect_and_sort_names();
while(p=name_from_list())
dump_file(p,-1);
/* if(!f_dironly) { */
blank_name_list();
while(p=name_from_list()) {
strcpy(buf,p);
if(p[strlen(p)-1]!='/')
strcat(buf,"/");
bufp=buf+strlen(buf);
for(q=gnu_list_name->dir_contents;q && *q;q+=strlen(q)+1) {
if(*q=='Y') {
strcpy(bufp,q+1);
dump_file(buf,-1);
}
}
}
/* } */
} else {
p = name_next(1);
if(!p)
dump_file(".", -1);
else {
do dump_file(p, -1);
while (p = name_next(1));
}
}
write_mangled();
write_eot();
close_archive();
if(f_gnudump)
write_dir_file();
name_close();
}
/*
* Dump a single file. If it's a directory, recurse.
* Result is 1 for success, 0 for failure.
* Sets global "hstat" to stat() output for this file.
*/
void
dump_file (p, curdev)
char *p; /* File name to dump */
int curdev; /* Device our parent dir was on */
{
union record *header;
char type;
extern char *save_name; /* JF for multi-volume support */
extern long save_totsize;
extern long save_sizeleft;
union record *exhdr;
char save_linkflag;
extern time_t new_time;
int sparse_ind = 0;
if(f_confirm && !confirm("add",p))
return;
/*
* Use stat if following (rather than dumping) 4.2BSD's
* symbolic links. Otherwise, use lstat (which, on non-4.2
* systems, is #define'd to stat anyway.
*/
#ifdef AIX
if (0 != f_follow_links ?
statx (p, &hstat, STATSIZE, STX_HIDDEN):
statx (p, &hstat, STATSIZE, STX_HIDDEN|STX_LINK))
#else
if (0 != f_follow_links? stat(p, &hstat): lstat(p, &hstat))
#endif /* AIX */
{
badperror:
msg_perror("can't add file %s",p);
badfile:
errors++;
return;
}
#ifdef AIX
if (S_ISHIDDEN (hstat.st_mode)) {
char *new = (char *)allocate (strlen (p) + 2);
if (new) {
strcpy (new, p);
strcat (new, "@");
p = new;
}
}
#endif /* AIX */
/* See if we only want new files, and check if this one is too old to
put in the archive. */
if( f_new_files
&& !f_gnudump
&& new_time>hstat.st_mtime
&& (hstat.st_mode&S_IFMT)!=S_IFDIR
&& (f_new_files>1 || new_time>hstat.st_ctime)) {
if(curdev<0) {
msg("%s: is unchanged; not dumped",p);
}
return;
}
#ifndef __MSDOS__
/* See if we are trying to dump the archive */
if(ar_dev && hstat.st_dev==ar_dev && hstat.st_ino==ar_ino) {
msg("%s is the archive; not dumped",p);
return;
}
#endif
/*
* Check for multiple links.
*
* We maintain a list of all such files that we've written so
* far. Any time we see another, we check the list and
* avoid dumping the data again if we've done it once already.
*/
if (hstat.st_nlink > 1) switch (hstat.st_mode & S_IFMT) {
register struct link *lp;
case S_IFREG: /* Regular file */
#ifdef S_IFCTG
case S_IFCTG: /* Contigous file */
#endif
#ifdef S_IFCHR
case S_IFCHR: /* Character special file */
#endif
#ifdef S_IFBLK
case S_IFBLK: /* Block special file */
#endif
#ifdef S_IFIFO
case S_IFIFO: /* Fifo special file */
#endif
/* First quick and dirty. Hashing, etc later FIXME */
for (lp = linklist; lp; lp = lp->next) {
if (lp->ino == hstat.st_ino &&
lp->dev == hstat.st_dev) {
char *link_name = lp->name;
/* We found a link. */
hstat.st_size = 0;
header = start_header(p, &hstat);
if (header == NULL) goto badfile;
while(!f_absolute_paths && *link_name == '/') {
static int link_warn = 0;
if (!link_warn) {
msg("Removing leading / from absolute links");
link_warn++;
}
link_name++;
}
strncpy(header->header.linkname,
link_name,NAMSIZ);
if(header->header.linkname[NAMSIZ-1]) {
char *mangled;
extern char *find_mangled();
mangled=find_mangled(link_name);
msg("%s: link name too long: mangled to %s",link_name,mangled);
strncpy(header->header.linkname,mangled,NAMSIZ);
}
header->header.linkflag = LF_LINK;
finish_header(header);
/* FIXME: Maybe remove from list after all links found? */
return; /* We dumped it */
}
}
/* Not found. Add it to the list of possible links. */
lp = (struct link *)malloc((unsigned)(sizeof(struct link)+strlen(p)));
if (!lp) {
if (!nolinks) {
msg(
"no memory for links, they will be dumped as separate files");
nolinks++;
}
}
lp->ino = hstat.st_ino;
lp->dev = hstat.st_dev;
strcpy(lp->name, p);
lp->next = linklist;
linklist = lp;
}
/*
* This is not a link to a previously dumped file, so dump it.
*/
switch (hstat.st_mode & S_IFMT) {
case S_IFREG: /* Regular file */
#ifdef S_IFCTG
case S_IFCTG: /* Contiguous file */
#endif
{
int f; /* File descriptor */
long bufsize, count;
long sizeleft;
register union re